package com.lzh.runke.core.aspect;

import com.lzh.runke.core.annotation.Escape;
import com.lzh.runke.core.entity.BaseEntity;
import com.lzh.runke.core.entity.spec.BaseSpec;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;

/**
 * 特殊符合转义
 *
 * @author tension 2023-05-11
 * @version 2.2.029+
 */
@Slf4j
@Aspect
@Component
public class EscapeAspect {
    @Before("execution(* com.lzh.runke..controller..*(..))")
    public void doBefore(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        if (ArrayUtils.isNotEmpty(args)) {
            Arrays.stream(args).forEach(arg -> {
                // 仅处理参数类型基类为 BaseSpec, BaseEntity
                if (arg instanceof BaseSpec || arg instanceof BaseEntity) {
                    escape(arg);
                }
            });
        }
    }

    private void escape(Object instance) {
        if (instance == null) {
            return;
        }
        List<Field> fields = FieldUtils.getAllFieldsList(instance.getClass());
        if (CollectionUtils.isNotEmpty(fields)) {
            fields.forEach(field -> {
                try {
                    Object fieldInstance = FieldUtils.readField(field, instance, true);
                    Escape escapeAnno = field.getAnnotation(Escape.class);
                    if (null != escapeAnno) {
                        String[] specialChars = escapeAnno.value();
                        if (ArrayUtils.isEmpty(specialChars)) {
                            log.error("{}: value 为空, 未指定需要转义的特殊字符, 特殊字符将不会被转义", Escape.class.getName());
                            return;
                        }
                        String fieldValue = (String) FieldUtils.readField(field, instance, true);
                        if (StringUtils.isBlank(fieldValue) || !StringUtils.containsAny(fieldValue, specialChars)) {
                            return;
                        }
                        for (String specialChar : specialChars) {
                            fieldValue = fieldValue.replaceAll(specialChar, "\\\\" + specialChar);
                        }
                        FieldUtils.writeField(field, instance, fieldValue, true);
                    }
                    if (fieldInstance instanceof BaseSpec || fieldInstance instanceof BaseEntity) {
                        escape(fieldInstance);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
    }
}
